home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / Tools / freeWAIS-sf-1.1 / ir / waisserver.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-12-13  |  26.6 KB  |  956 lines

  1. /* WIDE AREA INFORMATION SERVER SOFTWARE    
  2.    No guarantees or restrictions.  See the readme file for the full standard 
  3.    disclaimer.
  4.    5.29.90    Harry Morris, morris@think.com
  5. */
  6.  
  7. /* Copyright (c) CNIDR (see ../COPYRIGHT) */
  8.  
  9.  
  10. /* this file is a server process for a unix machine that takes input from 
  11.    standard in or from a socket and searches the local search engine on the 
  12.    unix box.
  13.    originally written by harry morris.
  14.    modified by brewster kahle. 7/90
  15.    6.xx.90    Brewster - initial implementation of stdio interface
  16.    7.xx.90    Patrick Bray - support for headers and forking processes
  17.    90.07.31    Ephraim - support for logging 
  18.  
  19.    91.03.03     Jonathan - set searchLog to log_out.
  20.    91.05.23    Jonathan - added fork process for indexer.
  21.                            Fixed version display so it exits.
  22.    91.05.25     Jonathan - added setuid.
  23.    
  24.    Tue Jul  9 12:11:02 1991 -- Michael Haberler mah@wu-wien.ac.at
  25.  
  26.                 Added semi-intelligent INFO database indexing (only done if
  27.         any of the .src files is newer than INFO.dct)
  28.         
  29.         Locking against multiple concurrent INFO rebuilds if 
  30.         running under inetd
  31.  
  32.         Use scandir() for directory operations
  33.  
  34.         Works under inetd as well as standalone. Here are my inetd.conf
  35.            entries (not the missing userid in the Ultrix inetd.conf!):
  36.  
  37.    hpux 7.0/800, Interactive/386 2.2.1:
  38.     z3950 stream tcp nowait root /usr/local/etc/waisserver waisserver -s \
  39.         -d /usr/logins/mah/wais-sources
  40.  
  41.    Ultrix 4.1:
  42.     z3950 stream tcp nowait /usr/local/etc/waisserver waisserver -s \
  43.         -d /usr/logins/mah/wais-sources
  44.  
  45.    Also, add the next line to /etc/services, and tickle your YP server:
  46.     z3950           210/tcp         # wide area information server (wais)
  47.  
  48.  * $Log: waisserver.c,v $
  49.  * Revision 1.20  1994/12/13  18:52:45  pfeifer
  50.  * chip@chinacat.unicom.com (Chip Rosenthal) patches.
  51.  * Excluding the merge of libinv and libwais
  52.  *
  53.  * Revision 1.19  1994/11/28  14:00:21  pfeifer
  54.  * typo
  55.  *
  56.  * Revision 1.18  1994/11/22  16:39:56  pfeifer
  57.  * "matthew (m.) holiday" <holiday@bnr.ca>: There's an fflush() call
  58.  * missing in file waisserver.c just before the call to rewind(in).  This
  59.  * was a reported issue in freeWais 0.3 with respect to HPUX, that
  60.  * doesn't seem to have made it across to freeWais-sf.
  61.  *
  62.  * Revision 1.17  1994/09/09  09:00:32  pfeifer
  63.  * Fixed the MAX_OCCURANCES - STOP_WORD_FLAG bug
  64.  *
  65.  * Revision 1.16  1994/09/05  10:18:59  pfeifer
  66.  * Removed buggy init_add_word call
  67.  *
  68.  * Revision 1.15  1994/09/05  10:17:32  pfeifer
  69.  * shm patch
  70.  *
  71.  * Revision 1.14  1994/08/23  12:34:00  pfeifer
  72.  * Made client fork #undef'able
  73.  * Fixed umr bug
  74.  *
  75.  * Revision 1.13  1994/08/13  16:55:21  pfeifer
  76.  * added call to sayiamhere
  77.  *
  78.  * Revision 1.12  1994/08/12  17:46:29  pfeifer
  79.  * initialize dataops in main with zeroes.
  80.  *
  81.  * Revision 1.11  1994/08/08  07:33:01  pfeifer
  82.  * Moved wais_log_file_name and waislogfile to cutil.[ch]
  83.  *
  84.  * Revision 1.10  1994/08/05  07:12:58  pfeifer
  85.  * Release beta 04
  86.  *
  87.  * Revision 1.8  1994/05/20  12:58:39  pfeifer
  88.  * beta
  89.  *
  90.  * Revision 1.7  1994/03/23  12:57:16  huynh1
  91.  * calling of openDatabase and init_add_word modified.
  92.  * patchlevel 07.
  93.  *
  94.  * Revision 1.6  1994/03/21  17:27:40  huynh1
  95.  * patchlevel 07.
  96.  *
  97.  * Revision 1.5  1994/03/11  15:29:34  huynh1
  98.  * write_src_structure modified.
  99.  * Patchlevel 05.
  100.  *
  101.  * Revision 1.4  1994/03/08  21:07:12  pfeifer
  102.  * Patchlevel 04
  103.  *
  104.  * Revision 1.3  93/07/21  18:52:39  warnock
  105.  * Renamed from server.c.
  106.  * Added STELAR-specific patches
  107.  * 
  108.  * Revision 1.2  93/07/01  19:19:53  warnock
  109.  * gethostname -> mygethostname
  110.  * 
  111.  * Revision 1.1  1993/02/16  15:05:35  freewais
  112.  * Initial revision
  113.  *
  114.  * Revision 1.48  92/05/10  14:47:39  jonathan
  115.  * Update for release.
  116.  * 
  117.  * Revision 1.47  92/05/06  17:34:01  jonathan
  118.  * Changed auto-indexing of .src files to use filename_finish_header_function.
  119.  * 
  120.  * Revision 1.46  92/05/04  17:18:32  jonathan
  121.  * Fixed use of merge_pathname in creating INFO database.
  122.  * 
  123.  * Revision 1.45  92/04/28  15:19:18  jonathan
  124.  * Added decoding of IP address to DNS name in init message handler.
  125.  * 
  126.  * Revision 1.44  92/03/26  18:26:41  jonathan
  127.  * Added extra arguments to index_text_file call.
  128.  * 
  129.  * Revision 1.43  92/03/07  19:41:47  jonathan
  130.  * Added IBM defines, courtesy mycroft@hal.gnu.ai.mit.edu,
  131.  * 
  132.  * Revision 1.42  92/03/05  07:07:58  shen
  133.  * add two more dummy arguments to call to init_search_engine
  134.  * 
  135.  * Revision 1.41  92/02/27  09:58:50  jonathan
  136.  * Put back in setting of core limit to max value, when SET_LIMIT is defined.
  137.  * 
  138.  * Revision 1.40  92/02/24  10:07:41  jonathan
  139.  * Removed reporting functions.
  140.  * 
  141.  * Revision 1.39  92/02/21  12:27:15  jonathan
  142.  * Changed logging of segmentation violation and bus errors to mark log with
  143.  * an error code, and close code.
  144.  * 
  145.  * Revision 1.38  92/02/21  11:00:45  jonathan
  146.  * Added wais_log_level
  147.  * 
  148.  * Revision 1.37  92/02/19  10:16:25  jonathan
  149.  * Added build_catalog to auto-indexer.
  150.  * 
  151.  * Revision 1.36  92/02/16  12:33:21  jonathan
  152.  * Removed code refering to NOINETNTOA, since we should use inet_ntoa.
  153.  * 
  154.  * Revision 1.35  92/02/16  12:05:18  jonathan
  155.  * Added code for GCC incompatibility in inet_ntoa (passing structure as
  156.  * pointer).
  157.  * 
  158.  * Revision 1.34  92/02/14  09:07:34  jonathan
  159.  * Set MAXNAPTIME to 0 so it won't sleep.  Changed the WLOG_ERROR to
  160.  * WLOG_WARNING in the log entry.
  161.  * 
  162.  * Revision 1.33  92/02/12  13:44:20  jonathan
  163.  * Added "$Log" so RCS will put the log message in the header
  164.  * 
  165.  * 
  166.  */
  167.  
  168. #define SERVER_DATE "Fri April 9 1993"
  169.  
  170. #ifndef lint
  171. static char *RCSid = "$Header: /usr/local/ls6/src+data/src/freeWAIS-sf/ir/RCS/waisserver.c,v 1.20 1994/12/13 18:52:45 pfeifer Exp $";
  172. #endif
  173.  
  174. #define INFO_DICT    "INFO.dct"
  175. #define LOCKFILE    "/tmp/INFO.lock" /* while re-indexing INFO */
  176. #define NAPTIME     1             /* seconds */
  177. #define MAXNAPTIME  0        /* Don't wait, just go on. */
  178.  
  179. #include "server.h"
  180. #include "sockets.h"
  181. /* #include <sys/types.h> */
  182. #include <sys/stat.h>
  183. #ifdef ultrix
  184. #include <sys/file.h>
  185. #else
  186. #ifdef _IBMR2
  187. #include <fcntl.h>
  188. #else /* ! _IBMR2 */
  189. #ifdef USG
  190. #ifdef HAVE_SYS_FCNTL_H
  191. #include <sys/fcntl.h>
  192. #else
  193. #include <fcntl.h>
  194. #endif /* HAVE_SYS_FCNTL_H */
  195. #else
  196. #include <sys/file.h>
  197. #endif
  198. #endif /* _IBMR2 */
  199. #endif /* else ultrix */
  200. #ifdef SYSV            
  201. #define SIGCHLD SIGCLD
  202. #endif
  203. #include <signal.h>
  204. /*#include <string.h> */
  205. #ifdef HAVE_SYS_SELECT_H
  206. #include <sys/select.h>
  207. #endif /* HAVE_SYS_SELECT_H */
  208. #include "irdirent.h"
  209. #include "panic.h"
  210. #include "ustubs.h"
  211. #include "transprt.h"
  212. #include "wmessage.h"
  213. #include "ir.h"
  214. #include "wprot.h"
  215. #include "cutil.h"
  216. #include "futil.h"
  217. #include "irext.h"
  218. #include "irsearch.h"
  219.  
  220. /* to create the INFO index */
  221. #include "irtfiles.h"
  222. #include "irfiles.h"
  223. #include "irhash.h"
  224. #include "version.h"
  225.  
  226. #include <errno.h>
  227. #ifdef Mach 
  228. extern int errno;
  229. #endif
  230.  
  231. static long bufferSize = BUFSZ; /* how much we are using
  232.                                    (we get one of these per process) */
  233.  
  234.  
  235. /* Bitmap association table -- LEB/HSTX 8/5/92 */
  236. #ifdef STELAR
  237. #define LOOKUP_TABLE /archives/stelar/abs/wais/bitmap.table
  238.  
  239. char *bitmap_table = "LOOKUP_TABLE";
  240.  
  241. /* char *bitmap_table = "/archives/stelar/abs/wais/bitmap.table"; */
  242. #endif /* STELAR */
  243.  
  244. /*---------------------------------------------------------------------------*/
  245.  
  246. #define TIMEOUT_LENGTH 3600 /* one hour timeout. */
  247. #define IDLE_TIME "1 hour"
  248.  
  249. void
  250. serve_client(in,out, index_directory)
  251. FILE* in;
  252. FILE* out;
  253. char *index_directory;
  254.   char buf[BUFSZ];        /* contains the message and header */
  255.   char *bufPtr ;        /* points at the begining of the z3950 */
  256.   long size;            /* bytes in the z3950 message */
  257.   WAISMessage header;        /* for storing the header */
  258.   long i;
  259.   long bytesLeft;
  260.   struct itimerval new, old;
  261.   long nextChar;
  262.  
  263.   new.it_interval.tv_sec = 0;
  264.   new.it_interval.tv_usec = 0;
  265.   new.it_value.tv_sec = TIMEOUT_LENGTH;
  266.   new.it_value.tv_usec = 0;
  267.  
  268.   bzero(buf, BUFSZ*sizeof(char)); /* avoid umr (up)/8/94 */
  269.   getitimer(ITIMER_REAL, &old);
  270.   while (TRUE)
  271.     {
  272.       /* try to read the header */
  273.       for (i = 0; i < HEADER_LENGTH; i++)
  274.     { 
  275.       setitimer(ITIMER_REAL, &new, NULL);
  276.       nextChar = fgetc(in);
  277.       if (nextChar == EOF)    /* my connection exited, so will I */
  278.         { 
  279.           return;
  280.         }
  281.       else
  282.         buf[i] = (char)nextChar;
  283.     }
  284.  
  285.       setitimer(ITIMER_REAL, &old, NULL);
  286.       /* parse the header */
  287.       readWAISPacketHeader(buf,&header);
  288.  
  289.       /* make sure we have the right version.  
  290.      If we dont, we dont know what to do. */
  291.       if (header.hdr_vers > HEADER_VERSION)
  292.     panic("Incompatable header versions (Current version: %c, supplied version: %c.", 
  293.           HEADER_VERSION, header.hdr_vers) ;
  294.  
  295.       /* determine the size of the z3950 message */
  296.       {
  297.     char length_array[11];
  298.     strncpy(length_array, header.msg_len, 10);
  299.     length_array[10] = '\0';
  300.     size = atol(length_array);
  301.       }
  302.  
  303.       /* set bufPtr to start the z3950 message */
  304.       bufPtr = buf + HEADER_LENGTH ;
  305.  
  306.       /* read the z3950 message */
  307.       for (i = 0; i < size ; i++) {
  308.     setitimer(ITIMER_REAL, &new, NULL);
  309.     buf[i + HEADER_LENGTH] = (char)fgetc(in) ;
  310.       }
  311.  
  312.       fflush(in);
  313.       rewind(in);
  314.  
  315.       /* decode the z3950 if necessary */
  316.       transportDecode((long)header.encoding,bufPtr,&size);
  317.      
  318.       /* XXX handle compression options */
  319.  
  320.       /* process it the z3950 */
  321.       bytesLeft = bufferSize;
  322.  
  323.       size = interpret_buffer(bufPtr,size,bufPtr,bytesLeft,
  324.                   &bufferSize,(long)header.hdr_vers,
  325.                   index_directory); 
  326.  
  327.       /* re-encode the message if necessary */
  328.       transportCode((long)header.encoding,bufPtr,&size); 
  329.  
  330.       /* XXX handle compression options */
  331.  
  332.       /* write the new header */
  333.       writeWAISPacketHeader(buf,size,
  334.                 (long)header.msg_type,header.server,
  335.                 (long)header.compression,(long)header.encoding,
  336.                 (long)header.hdr_vers);
  337.  
  338.       /* write the whole response to the output file */
  339.       for (i = 0; i < size + HEADER_LENGTH; i++)
  340.     fputc(buf[i],out) ;
  341.  
  342.       fflush(out);        /* flush any file buffers */
  343.       rewind(out);        /* reset the file for read */
  344.  
  345.     }
  346. }
  347.  
  348. /*---------------------------------------------------------------------------*/
  349.  
  350. #ifndef ISC
  351. static void breakKey _AP((long s1,long s2,struct sigcontext* s3,char* s4));
  352. #endif
  353.  
  354. static void
  355. breakKey (s1,s2,s3,s4)
  356. long s1;
  357. long s2;
  358. struct sigcontext *s3;
  359. char *s4;
  360. {
  361.   if(0 != finished_search_engine())
  362.     panic("unable to close search engine");
  363.   panic ("got a ^c");
  364. }
  365.  
  366. /*---------------------------------------------------------------------------*/
  367.  
  368. void
  369. childhandler(sig, code, scp, addr)
  370. long sig, code;
  371. struct sigcontext *scp;
  372. char *addr;
  373. {
  374.   wait(NULL);            /* give the kid a decent burial */
  375.   signal (SIGCHLD, childhandler);  /* Dave Judd - IRIX requires resetting signal */
  376. }
  377.  
  378. /*---------------------------------------------------------------------------*/
  379.  
  380. void
  381. alarmhandler(sig, code, scp, addr)
  382. long sig, code;
  383. struct sigcontext *scp;
  384. char *addr;
  385. {
  386.   waislog(WLOG_HIGH, WLOG_CLOSE,
  387.       "Server idle longer %s. Closing server and exiting.", IDLE_TIME);
  388.   if(0 != finished_search_engine())
  389.     panic("unable to close search engine");
  390.   exit(0);
  391. }
  392.  
  393. /*---------------------------------------------------------------------------*/
  394.  
  395. void
  396. seghandler(sig, code, scp, addr)
  397. long sig, code;
  398. struct sigcontext *scp;
  399. char *addr;
  400. {
  401.   waislog(WLOG_HIGH, WLOG_ERROR, "Segmentation violation.");
  402.   waislog(WLOG_HIGH, WLOG_CLOSE, "Bummer. Closing server and exiting.");
  403. #ifdef DUMPCORE
  404.     abort();
  405. #else
  406.   exit(-1);
  407. #endif
  408. }
  409.  
  410. /*---------------------------------------------------------------------------*/
  411.  
  412. void
  413. bushandler(sig, code, scp, addr)
  414. long sig, code;
  415. struct sigcontext *scp;
  416. char *addr;
  417. {
  418.   waislog(WLOG_HIGH, WLOG_ERROR, "Bus error.");
  419.   waislog(WLOG_HIGH, WLOG_CLOSE, "Bummer. Closing server and exiting.");
  420. #ifdef DUMPCORE
  421.     abort();
  422. #else
  423.   exit(-1);
  424. #endif
  425. }
  426.  
  427. /*---------------------------------------------------------------------------*/
  428.  
  429. #include <pwd.h>
  430.  
  431. int finduid(name)
  432. char *name;
  433. {
  434.   struct passwd *pwent;
  435.  
  436.   if ((pwent = getpwnam(name)) == NULL) {
  437.     return -1;
  438.   }
  439.  
  440.   return(pwent->pw_uid);
  441. }
  442.  
  443. static  char *index_dir = NULL;
  444. static  time_t info_change_time;
  445. static  int indexing_needed = 0;
  446. static  char *info_dict = INFO_DICT;
  447.  
  448. extern int alphasort();
  449.  
  450. /* selecttion function for scandir()
  451.  * trigger on ".src" extension, regular file, and != "INFO.src"
  452.  * Indexing is needed if any of the .src files is younger than 
  453.  * INFO.dct
  454.  */
  455. static int
  456. srcfiles(e)
  457.     struct dirent *e;
  458. {
  459.     struct stat sb;
  460.     char *lastdot = strrchr(e->d_name,'.');
  461.     int candidate;
  462.  
  463.     candidate =    lastdot && 
  464.           (stat(merge_pathnames(e->d_name,index_dir), &sb) >= 0) && 
  465.           ((sb.st_mode & S_IFMT) == S_IFREG) &&
  466.           !strcmp(lastdot,source_ext) && 
  467.           strcmp(e->d_name,info_dict); /* whew */
  468.  
  469.         if (candidate) {
  470.         indexing_needed |= (sb.st_mtime > info_change_time);
  471.         return 1;
  472.     }
  473.     return 0;
  474. }
  475.  
  476.  
  477. /*---------------------------------------------------------------------------*/
  478.  
  479. #ifdef SET_LIMIT
  480. #include <sys/resource.h>
  481. #endif
  482.  
  483. #define INDEX_FORK
  484.  
  485. extern char *inet_ntoa ();
  486. extern char *syslog_name;
  487.  
  488. void
  489. main(argc,argv)
  490. int argc;
  491. char* argv[];
  492. { FILE *file;
  493.   long socket;
  494.   char *next_argument = next_arg(&argc, &argv), *command_name;
  495.   boolean use_stdio = TRUE;        /* default is true */
  496.   /* char *wais_log_file_name = NULL; */    /* name of file for error output */
  497.   int child_proc;        /* for the child process id */
  498.   char *uid_name = "root";    /* user id so setuid if root */
  499.   int uid = 0;        /* if not specified, leave as root. */
  500.   int child;
  501.   long cm_mem_percent = 0;  /* default */
  502.   struct stat statbuf;
  503.   struct dirent **list;
  504.   int naptime = 0;
  505.   extern char *sys_errlist[];
  506.   extern void filename_finish_header_function();
  507.   dataopsrec    dataops;  
  508.  
  509. #ifdef CACHE_SYN
  510.   int cachesyn = 0;
  511. #endif
  512.  
  513. #ifdef SET_LIMIT
  514.   struct rlimit rlp;
  515.  
  516.   getrlimit(RLIMIT_CORE, &rlp);
  517.   rlp.rlim_cur = rlp.rlim_max;
  518.   setrlimit(RLIMIT_CORE, &rlp);
  519.   getrlimit(RLIMIT_DATA, &rlp);
  520.   rlp.rlim_cur = rlp.rlim_max;
  521.   setrlimit(RLIMIT_DATA, &rlp);
  522. #endif
  523.  
  524. /* dgg -- must duplicate mods to irbuild.c, here is mini-build of INFO.src */
  525.   bzero(&dataops,sizeof(dataops));
  526.   dataops.separator_function= NULL;
  527.   dataops.header_function= NULL;
  528.   dataops.date_function= NULL;
  529.   dataops.finish_header_function= filename_finish_header_function;
  530.   dataops.type= "WSRC";
  531.   dataops.wordDelimiter= wordbreak_notalnum;
  532.   dataops.addseparatorwords= false;
  533.   dataops.extraheaderweight= true;
  534.   dataops.repeat_weight= 1;
  535.   dataops.minwordlen= 2;
  536.   stop_list_file("\0");
  537.   gDelimiters[0]= '\0';  
  538.   wordDelimiter= wordbreak_notalnum;   
  539. /* dgg -- end new inits */
  540.  
  541.   tcp_port = 210;            /* tcp_port to use */
  542.   command_name = next_argument;
  543.   syslog_name = (syslog_name = (char *)rindex(command_name, '/')) ? (syslog_name + 1) : command_name;
  544.   host_name[0] = 0;
  545.   host_address[0] = 0;
  546.  
  547.   server_name = s_malloc(255);
  548.   mygethostname(server_name, 255);
  549.  
  550.   wais_pid = getpid();
  551.  
  552.   if (!strcmp(command_name, "waisserver.d")) {
  553.     struct sockaddr_in source;
  554.     int sourcelen;
  555.  
  556.     sourcelen = sizeof(struct sockaddr_in);
  557.  
  558.     if (!getpeername(fileno(stdout),&source,&sourcelen)) {
  559.       struct hostent *peer = NULL;
  560.  
  561. #ifdef __DGUX__
  562.       peer = gethostbyaddr((char *)&source.sin_addr.s_addr, 4, AF_INET);
  563. #else
  564.       peer = gethostbyaddr(&source.sin_addr, 4, AF_INET);
  565. #endif
  566.  
  567.       if(peer != NULL) {
  568.     sprintf(host_name, "%s", peer->h_name);
  569.  
  570.     sprintf(host_address, "%s",
  571. #if defined(sparc) && defined(__GNUC__) && defined(INET_NTOA_WITH_POINTER)
  572.         inet_ntoa(&source.sin_addr)
  573. #else
  574.         inet_ntoa(source.sin_addr)
  575. #endif                /* sparc */
  576.         );
  577.       }
  578.     }
  579.     else sprintf(host_address, "Error getting socket: %d, %s.", errno, sys_errlist[errno]);
  580.  
  581.    use_stdio = TRUE;
  582.   }
  583.  
  584.   if (argc == 0){
  585. #ifdef CACHE_SYN
  586.     fprintf(stderr,"Usage: %s [-p [port_number]] [-s] [-d directory] [-u user] [-cmmem number] [-cachesyn] [-v]\n",
  587. #else
  588.     fprintf(stderr,"Usage: %s [-p [port_number]] [-s] [-d directory] [-u user] [-cmmem number] [-v]\n",
  589. #endif
  590.        command_name);
  591.     fprintf(stderr," -p [port] listen to the port.  If the port is supplied, then\n");
  592.     fprintf(stderr,"    that tcp_port number is used.  If it is not supplied \n");
  593.     fprintf(stderr,"    then the Z39.50 port (210) is used.\n");
  594.     fprintf(stderr," -d directory: means to use the directory as the source of databases.\n");
  595.     fprintf(stderr,"    Defaults to the current directory.\n");
  596.     fprintf(stderr," -e [file]: set log output to file, or /dev/null if not specified.\n");
  597.     fprintf(stderr," -l log_level: set log level.  0 means log nothing,\n");
  598.     fprintf(stderr,"    10 [the default] means log everything.\n");
  599.     fprintf(stderr," -s means listen to standard I/O for queries.  This is the default\n");
  600.     fprintf(stderr," -u user: if started as root, setuid to user after startup.\n");
  601.     fprintf(stderr," -cmmem number: percentage of CM memory to use (CM code only).\n");
  602. #ifdef CACHE_SYN
  603.     fprintf(stderr," -cachesyn: cache synonym table in shared memory (default is don't cache)\n");
  604. #endif
  605.     fprintf(stderr," -v prints the version.\n");
  606.     exit(1);
  607.   }
  608.   if(NULL == (next_argument = next_arg(&argc, &argv))){
  609.     fprintf(stderr,"No arguments specified\n");
  610.     exit(0);
  611.   }
  612.   while((next_argument != NULL) &&
  613.     ('-' == next_argument[0])){
  614.  
  615.     /* then we have an argument to process */
  616.     if (0 == strcmp("-p", next_argument)){
  617.       char *peek_argument = peek_arg(&argc, &argv);
  618.       use_stdio = FALSE;
  619.       if ((NULL != peek_argument) && /* if we are not out of args */
  620.       ('-' != peek_argument[0])){ { /* and the next isn't an option... */
  621.         /* get the port number */
  622.         tcp_port = atoi(next_arg(&argc, &argv));
  623.       }            /* end if (explicit tcp_port) */
  624.                     }
  625.     }                /* end if (-p) */
  626.     else if (0 == strcmp("-s", next_argument)){
  627.       use_stdio = TRUE;
  628.     }                /* end if (-s) */
  629.  
  630.     else if (0 == strcmp("-e", next_argument)) {
  631.       char *peek_argument = peek_arg(&argc, &argv);
  632.       wais_log_file_name = "/dev/null"; /* default to /dev/null */
  633.       if ((peek_argument != NULL) &&
  634.       ('-' != peek_argument[0])) {
  635.     wais_log_file_name = next_arg(&argc, &argv);
  636.       }                /* end if (explicit log file) */
  637.     }                /* end if (-e) */
  638.     else if (0 == strcmp("-l", next_argument)) {
  639.       wais_log_level = atol(next_arg(&argc, &argv));
  640.     }                /* end if (-l) */
  641.     else if (0 == strcmp("-d", next_argument)) {
  642.       index_dir = next_arg(&argc, &argv);
  643.     }
  644.     else if (0 == strcmp("-v", next_argument)) {
  645.       fprintf(stderr,"%s: %s, %s\n", command_name, VERSION, SERVER_DATE);
  646.     }
  647.     else if (0 == strcmp("-u", next_argument)) {
  648.       uid_name = next_arg(&argc, &argv);
  649.       if((uid = finduid(uid_name)) < 0)
  650.     panic("Couldn't find user %s.", uid_name);
  651.     }
  652.     else if(0 == strcmp("-cmmem", next_argument)){
  653.       if(NULL == (next_argument = next_arg(&argc, &argv)))
  654.     panic("Expected a number (1-100) for percentage of memory to use");
  655.       cm_mem_percent = atol(next_argument);
  656.       if(cm_mem_percent < 1)
  657.     panic("The -cmmem argument should not be less than 1 and less than 100");
  658.       if(cm_mem_percent > 100)
  659.     panic("Warning: The -cmmem parameter was %ld%%. It should be between 1-100.", cm_mem_percent);
  660.     }
  661. #ifdef CACHE_SYN
  662.     else if (0 == strcmp("-cachesyn", next_argument)) {
  663.       cachesyn = 1;
  664.     }
  665. #endif
  666.     else{
  667.       panic("Don't recognize the %s option", next_argument);
  668.     }
  669.     next_argument = next_arg(&argc, &argv);
  670.   }                /* end while (more arguments) */
  671.  
  672.   if (use_stdio && wais_log_file_name == NULL) 
  673.     wais_log_file_name = "/dev/null";
  674.  
  675.   if (wais_log_file_name == NULL) 
  676.     waislogfile = stderr;
  677.   else waislogfile = NULL;
  678.   
  679.   index_dir = index_dir ? index_dir : ".";  
  680.   info_dict = s_strdup(merge_pathnames(info_dict,index_dir));
  681.  
  682.   if(0 != init_search_engine(index_dir, false, true, cm_mem_percent,0,0))
  683.     panic("unable to initialize search engine");
  684.   
  685.   /* remember timestamp on INFO.dct if rebuilding needed 
  686.    * If it doesnt exist, it's assumed to be *very* old, to force
  687.    * re-indexing
  688.    */
  689.   info_change_time = (stat(info_dict,&statbuf) == -1) ? 0 : statbuf.st_mtime;
  690.   
  691.   /* compare with candidates */
  692.  
  693.   if (scandir(index_dir, &list, srcfiles, alphasort) < 0) {
  694.       waislog(WLOG_HIGH, WLOG_ERROR, 
  695.           "Error: reading directory %s, %s", 
  696.           index_dir, sys_errlist[errno]);
  697.       indexing_needed = FALSE;
  698.   }
  699.   
  700.   /* ok. we know if we need indexing, 
  701.    * and have all the filenames. 
  702.    */
  703.   
  704.   if (info_change_time == 0) indexing_needed = TRUE;
  705.   if (indexing_needed) {
  706. #ifndef DO_NOT_TELL_ABOUT_ME
  707.     extern int sayiamhere _AP(());
  708.     sayiamhere();
  709. #endif
  710.  
  711.     /* Time to re-index,
  712.      * aquire the lock 
  713.      */
  714.     waislog(WLOG_MEDIUM, WLOG_INDEX,
  715.         "re-indexing needed, info_change_time=%d",info_change_time); 
  716.  
  717.     if (open(LOCKFILE, O_WRONLY|O_CREAT|O_EXCL,0666) == -1) {
  718.       
  719.       /* already locked by somebody else
  720.        * spin  till she finishes
  721.        */
  722.       while (!(stat(LOCKFILE,&statbuf) == -1)) {
  723.     sleep(NAPTIME);
  724.     naptime += NAPTIME;
  725.     waislog(WLOG_MEDIUM, WLOG_INFO,
  726.         "INFO locked, waiting since %d seconds", naptime);
  727.     if (naptime  > MAXNAPTIME)  {
  728.  
  729.       waislog(WLOG_HIGH, WLOG_WARNING,
  730.           "Warning - lockfile %s won't go away after %d seconds, not reindexing.", 
  731.           LOCKFILE, naptime);
  732.       break;
  733.     }
  734.       }
  735.       /* if lockfile went away, assume INFO.* build finished
  736.        * so just use it
  737.        */
  738.     } else {            /* we aquired the lock, so rebuild database  */
  739.       
  740. #ifdef INDEX_FORK
  741.       if (!(child = fork())) {
  742. #endif
  743.     database *db;
  744.     struct dirent **s = list;
  745.     char filename[MAX_FILENAME_LEN], *dbname;
  746.  
  747.     waislog(WLOG_MEDIUM, WLOG_INDEX,
  748.         "Creating INFO database, pid=%d",getpid());
  749.     dbname = s_strdup(merge_pathnames("INFO",    index_dir));
  750. #ifdef FIELDS /* tung, 3/94 */
  751.     db = openDatabase(dbname, true, false, false); 
  752. #else
  753.         db = openDatabase(dbname, true, false);
  754. #endif
  755.     s_free(dbname);
  756.  
  757.     init_add_word(db, 0, 100000L);
  758.  
  759.     while (*s) {        /* index it */
  760.       strncpy(filename, index_dir, MAX_FILENAME_LEN);
  761.       if(index_dir[strlen(index_dir) -1] != '/')
  762.         strncat(filename, "/", MAX_FILENAME_LEN);
  763.       strncat(filename, (*s)->d_name, MAX_FILENAME_LEN);
  764.       waislog(WLOG_MEDIUM, WLOG_INDEX,
  765.           "Indexing %s", filename);
  766.       index_text_file(filename, &dataops, db, true, false,
  767.               false, true
  768. #ifdef FIELDS /* tung, 5/94 */ 
  769.               ,-1
  770. #endif
  771.               );    
  772.       s++;
  773.     }
  774.     freedir(list);        /* array of filenames */
  775.           
  776.     if(!probe_file(source_filename(filename, db)))
  777.       write_src_structure(source_filename(filename, db),
  778.                   "INFO", "WSRC", NULL, 0L, true, 
  779. #ifdef FIELDS /* tung, 3/94 */                              
  780.                               tcp_port, db);
  781. #else
  782.                               tcp_port);
  783. #endif
  784.     finished_add_word(db);
  785.     build_catalog(db);
  786.     closeDatabase(db);
  787.     if (unlink(LOCKFILE))
  788.       panic("Indexer: cant unlink lockfile!\n");
  789.     waislog(WLOG_MEDIUM, WLOG_INDEX,
  790.         "Indexer pid=%d done", getpid());
  791.           
  792. #ifdef INDEX_FORK
  793.     exit(0);        /* indexing child */
  794.       }
  795.       else if (child == -1) {
  796.     waislog(WLOG_HIGH, WLOG_ERROR,
  797.         "Unable to fork for indexer.");
  798.     exit(1);
  799.       }
  800.       /* wait for child process */
  801.       else while (wait(0) != child) ; /* do nothing */
  802. #endif      
  803.     }
  804.   }
  805.  
  806.  
  807.   if (use_stdio == TRUE) {
  808.     if(host_address[0] != 0){
  809.       waislog(WLOG_MEDIUM, WLOG_CONNECT,
  810.           "Accepted connection from: %s [%s], %s",
  811.           host_name, host_address, VERSION);
  812.     }
  813.     else{
  814.       waislog(WLOG_MEDIUM, WLOG_CONNECT,
  815.           "Couldn't determine peer connection. %s", VERSION);
  816.     }
  817.  
  818.     if ( server_security(index_dir,NULL) != true ){
  819.       waislog(WLOG_HIGH, WLOG_INFO,"Closing down server");
  820.       exit(-1);
  821.      }
  822.  
  823.   }
  824.   else{
  825.     waislog(WLOG_MEDIUM, WLOG_INFO, "Running server %s", VERSION);
  826.   }
  827.  
  828.   signal(SIGINT, breakKey);
  829.  
  830.   signal(SIGCHLD, childhandler);      /* XXX dont really need this any more */
  831.   signal(SIGALRM, alarmhandler);
  832.  
  833.   signal(SIGSEGV, seghandler);
  834.  
  835.   signal(SIGBUS, bushandler);
  836.  
  837.   if(use_stdio == FALSE)
  838.    { 
  839.      if (tcp_port < 1024 && getuid() != 0) {
  840.        waislog(WLOG_HIGH, WLOG_ERROR,
  841.            "Error opening port %d:  Must be superuser to use a port < 1024",
  842.            tcp_port);
  843.        exit(-1);
  844.      }
  845.  
  846.      open_server(tcp_port,&socket,BUFSZ);
  847.  
  848. #ifdef SECURE_SERVER
  849.      /* if root, setuid to user specified id. */
  850.      if (uid > 0 && getuid() == 0)  {
  851.        waislog(WLOG_MEDIUM, WLOG_INFO,
  852.            "Setting uid to %s.", uid_name);
  853.         if (wais_log_file_name && *wais_log_file_name &&
  854.         chown(wais_log_file_name,uid,getgid()) < 0)
  855.      waislog(WLOG_HIGH, WLOG_ERROR,
  856.          "Unable to chown log file to %s!", uid_name);
  857.        if ( 0 > setuid(uid)) {
  858.      waislog(WLOG_HIGH, WLOG_ERROR,
  859.          "Unable to setuid to %s!  Exiting.", uid_name);
  860.      exit(-1);
  861.        }
  862.      }
  863. #endif
  864.  
  865. #ifdef CACHE_SYN
  866.      if (cachesyn) {
  867.        /* create and attach master shared memory segment containing info
  868.     * on cached synonyms (see synonym.c) */
  869.        int shm_key = 1, shm_cnt = 0;
  870.        char *pcs = NULL;
  871.        t_cacheSyn *cs = NULL;
  872.        cacheSynId = -1;
  873.        while (cacheSynId == (-1)) {
  874.      cacheSynId = shmget (shm_key, MAX_SYN_CACHE * sizeof(t_cacheSyn), 
  875.                   0644 | IPC_CREAT | IPC_EXCL);
  876.      if (cacheSynId == (-1) && errno != EEXIST) 
  877.         break;
  878.      shm_key++;
  879.        }
  880.        if (cacheSynId <= 0) {
  881.      cacheSynId = 0;
  882.      waislog (WLOG_HIGH, WLOG_WARNING, 
  883.           "Warning: cannot get shared memory area for synonyms, caching disabled");
  884.        }
  885.        else {
  886.      /* get shared memory for and initialize t_cacheSyn structure */
  887.      if ((pcs = (char *) shmat (cacheSynId, 0, 0)) == ((char *)-1)) {
  888.        cacheSynId = 0;
  889.        waislog (WLOG_HIGH, WLOG_WARNING, 
  890.             "Warning: cannot attatch shared memory segment for synonyms, caching disabled");
  891.      }
  892.      else {
  893.        for (shm_cnt = 0; shm_cnt < MAX_SYN_CACHE; 
  894.         shm_cnt++, pcs += sizeof(t_cacheSyn)) {
  895.          cs = (t_cacheSyn *) pcs;
  896.          cs->id = 0;
  897.          (cs->synfile)[0] = '\0';
  898.        }
  899.      }
  900.        }
  901.      }
  902. #endif
  903.  
  904.      while (TRUE) { /* be a server for several connections */
  905.        accept_client_connection(socket,&file);
  906.       
  907. #ifdef QUERY_FORK
  908.        if ((child_proc = fork()) == 0) {
  909. #endif          
  910.           /* grandson handles this connection
  911.            * double-fork takes care of zombies 
  912.            */
  913. #ifdef QUERY_FORK
  914.           if ((child_proc = fork()) == 0) { 
  915. #endif
  916.         wais_pid = getpid();
  917.         log_line = 0;
  918.         serve_client(file, file, index_dir);
  919.         /* but leaves server up */
  920.         close_client_connection(file);
  921.         close_server(socket);
  922.         /* just exits this child */
  923.         waislog(WLOG_MEDIUM, WLOG_CLOSE,
  924.             "Done handling client");
  925. #ifdef QUERY_FORK
  926.         exit(0);
  927.           } else {
  928.         /* son: orphans the grandchild, so init picks up 
  929.          * the exit status
  930.          */
  931.         exit(0);
  932.           }
  933.           } else {
  934.           waislog(WLOG_MEDIUM, WLOG_INFO,
  935.               "Child PID = %d", child_proc);
  936.           close_client_connection(file);     /* parent shouldn't keep the file */
  937.       }
  938. #endif
  939.       }
  940.    }
  941.   else if(use_stdio == TRUE)
  942.    { /* connections on stdio don't use child processes yet */
  943.      serve_client(stdin, stdout, index_dir);
  944.      waislog(WLOG_MEDIUM, WLOG_CLOSE,
  945.          "Done handling client");
  946.       /* close the whole thing */
  947.      if(0 != finished_search_engine())
  948.        panic("unable to close search engine");
  949.      exit(0);
  950.    }
  951. }
  952.  
  953. /*---------------------------------------------------------------------------*/
  954.  
  955.